/*
 * libmad - MPEG audio decoder library
 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: minimad.c,v 1.4 2004/01/23 09:41:32 rob Exp $
 */

# include <stdio.h>
# include <unistd.h>
# include <sys/stat.h>
# include <sys/mman.h>
# include <sys/soundcard.h>
# include <sys/ioctl.h>
# include <errno.h>
# include <fcntl.h>
# include <pthread.h>
# include <string.h>
# include <stdlib.h>
# include <math.h>

# include "mad.h"
# include "integer_fft.h"

#define LINEAR
//#define ST
/*
 * This is perhaps the simplest example use of the MAD high-level API.
 * Standard input is mapped into memory via mmap(), then the high-level API
 * is invoked with three callbacks: input, output, and error. The output
 * callback converts MAD's high-resolution PCM samples to 16 bits, then
 * writes them to standard output in little-endian, stereo-interleaved
 * format.
 */

//是否解析完标志
int decode_finish = 0;
//解码线程使用的缓冲区
short buf[1200*2];
//fft处理的数据副本
short fft_buf[1024*2];
//条件变量初始化
pthread_mutex_t condmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int soundfd;

static int decode(unsigned char const *, unsigned long);
static void set_dsp();
static void frequency(short[], int);

//fft线程函数
void* fft_threadfunc(void* arg);

int main(int argc, char *argv[])
{
	//线程相关
	int res;
	pthread_t fft_thread;
	pthread_attr_t thread_attr;

	struct stat stat;
	void *fdm;
#ifndef ST
	res = pthread_attr_init(&thread_attr);
	if(res != 0){
		perror("Attribute creation failed");
		exit(EXIT_FAILURE);
	}
	res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
	if(res != 0){
		perror("setting attribute failed");
		exit(EXIT_FAILURE);
	}
	res = pthread_create(&fft_thread, &thread_attr, fft_threadfunc, NULL);
	if(res != 0){
		perror("thread create failed");
		exit(EXIT_FAILURE);
	}
	pthread_attr_destroy(&thread_attr);
#endif

	if (argc != 1)
		return 1;

	if (fstat(STDIN_FILENO, &stat) == -1 ||
		stat.st_size == 0)
		return 2;

	fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0);
	if (fdm == MAP_FAILED)
		return 3;

	set_dsp();

	decode(fdm, stat.st_size);

	if (munmap(fdm, stat.st_size) == -1)
		return 4;
#ifndef ST
	pthread_mutex_destroy(&condmutex);
	pthread_cond_destroy(&cond);
#endif
	return 0;
}

/*
 * fft线程函数
 */
void* fft_threadfunc(void* arg){
	//short fft_buf[1024*2];
	static fixed real[1024], imag[1024];
	int i;
	while(0 == decode_finish){
		pthread_mutex_lock(&condmutex);
		pthread_cond_wait(&cond, &condmutex);
		
		for(i = 0;i < 1024;i++){
			real[i] = fft_buf[2*i];
			imag[i] = 0;
		}
		fix_fft(real,imag,10,0);
		for(i = 0;i < 1024;i++){
			real[i] = sqrt(real[i]*real[i]+imag[i]*imag[i]);
		}
		frequency(real,1024);
		pthread_mutex_unlock(&condmutex);
	}
	pthread_exit(NULL);
}

/*
 * 设置声卡
 */
static void set_dsp(){
	int rate = 44100;
	int format = AFMT_S16_LE;
	int channels = 2;
	soundfd = open("/dev/dsp", O_WRONLY);
	if(soundfd == -1){
		printf("errno to open dsp, errno=%d\n", errno);
	}
	ioctl(soundfd, SNDCTL_DSP_SPEED, &rate);
	ioctl(soundfd, SNDCTL_DSP_SETFMT, &format);
	ioctl(soundfd, SNDCTL_DSP_CHANNELS, &channels);
}

/*
 * 写数据到声卡
 */
int writedsp(int c){
	return write(soundfd, (char*)&c, 1);
}

/*
 * This is a private message structure. A generic pointer to this structure
 * is passed to each of the callback functions. Put here any data you need
 * to access from within the callbacks.
 */

struct buffer {
  unsigned char const *start;
  unsigned long length;
};

/*
 * This is the input callback. The purpose of this callback is to (re)fill
 * the stream buffer which is to be decoded. In this example, an entire file
 * has been mapped into memory, so we just call mad_stream_buffer() with the
 * address and length of the mapping. When this callback is called a second
 * time, we are finished decoding.
 */

static
enum mad_flow input(void *data,
		    struct mad_stream *stream)
{
  struct buffer *buffer = data;

  if (!buffer->length)
    return MAD_FLOW_STOP;

  mad_stream_buffer(stream, buffer->start, buffer->length);

  buffer->length = 0;

  return MAD_FLOW_CONTINUE;
}

/*
 * The following utility routine performs simple rounding, clipping, and
 * scaling of MAD's high-resolution samples down to 16 bits. It does not
 * perform any dithering or noise shaping, which would be recommended to
 * obtain any exceptional audio quality. It is therefore not recommended to
 * use this routine if high-quality output is desired.
 */

static inline
signed int scale(mad_fixed_t sample)
{
  /* round */
  sample += (1L << (MAD_F_FRACBITS - 16));

  /* clip */
  if (sample >= MAD_F_ONE)
    sample = MAD_F_ONE - 1;
  else if (sample < -MAD_F_ONE)
    sample = -MAD_F_ONE;

  /* quantize */
  return sample >> (MAD_F_FRACBITS + 1 - 16);
}

/*
 * This is the output callback function. It is called after each frame of
 * MPEG audio data has been completely decoded. The purpose of this callback
 * is to output (or play) the decoded PCM audio.
 */

static
enum mad_flow output(void *data,
		     struct mad_header const *header,
		     struct mad_pcm *pcm)
{
  int i;
  unsigned int nchannels, nsamples;
  mad_fixed_t const *left_ch, *right_ch;
  /* pcm->samplerate contains the sampling frequency */

  nchannels = pcm->channels;
  nsamples  = pcm->length;
  left_ch   = pcm->samples[0];
  right_ch  = pcm->samples[1];

  i = 0;

  while (nsamples--) {
    signed int sample;

    /* output sample(s) in 16-bit signed little-endian PCM */

    sample = scale(*left_ch++);
    //putchar((sample >> 0) & 0xff);
    //putchar((sample >> 8) & 0xff);
	buf[i] = sample & 0xFFFF;

    if (nchannels == 2) {
      sample = scale(*right_ch++);
      //putchar((sample >> 0) & 0xff);
      //putchar((sample >> 8) & 0xff);
	  buf[++i] = sample & 0xFFFF;
    }
	i++;
  }
  //write(soundfd, &buf[0], i*2);

  //拷贝到fft_buf
#ifndef ST
  pthread_mutex_lock(&condmutex);
	memcpy(fft_buf, buf, 1024*2);
	pthread_cond_signal(&cond);
  pthread_mutex_unlock(&condmutex);
#endif
  write(soundfd, &buf[0], i*2);

  /*
  for(i = 0;i < 1024;i++){
	  x[i].x=buf[i*2];
	  x[i].y = 0;
  }
  fft(1024,x,X);
  c_abs(X,out,1024);
  for (i = 0; i < 1024; i++) {
	out[i] = out[i] / (1 << 17);
  }
  frequency(out, 1024);
  */
  return MAD_FLOW_CONTINUE;
}

static void frequency(short freq[], int n) {
	static int cnt = 0;
	int h = 20, w = 64, i, j;
	int num[64];
	static int div[64]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
          24,25,26,27,28,29,30,31,32,33,34,35,36,38,42,46,51,56,62,69,77,85,94,104,114,127,140,155,171,189,
         209,230,254,281,311,343,379,419,462,511};
	if(freq[0]==0){
		num[0] = 0;
	}
	else 
#ifdef LINEAR
		num[0]=freq[0]/128;
#else
		num[0]=(int)(log10(freq[0])*4);
#endif
    for(i = 1;i < 64;i++){
		num[i] = 0;
		j = div[i-1]+1;
		while(j<=div[i]){
			num[i]+=freq[j];
			j++;
		}
		num[i]/=(div[i]-div[i-1]);
		if(num[i]!=0){
#ifdef LINEAR
			num[i]=freq[i]/128;
#else
			num[i]=(int)(log10(freq[i])*4);
#endif
		}
	}
	printf("%d\n", cnt++);
	for (i = 0; i < h; i++) {
		for (j = 0; j < w; j++) {//第j行，到达h-j的时候输出一个字符
			if (num[j] >= h - i) {
				printf("8");
			}
			else {
				printf(" ");
			}
		}
		printf("\n");
	}
	printf("\033[%dA", h+1);
}

/*
 * This is the error callback function. It is called whenever a decoding
 * error occurs. The error is indicated by stream->error; the list of
 * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
 * header file.
 */

static
enum mad_flow error(void *data,
		    struct mad_stream *stream,
		    struct mad_frame *frame)
{
  struct buffer *buffer = data;

  /*fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
	  stream->error, mad_stream_errorstr(stream),
	  stream->this_frame - buffer->start);*/

  /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */

  return MAD_FLOW_CONTINUE;
}

/*
 * This is the function called by main() above to perform all the decoding.
 * It instantiates a decoder object and configures it with the input,
 * output, and error callback functions above. A single call to
 * mad_decoder_run() continues until a callback function returns
 * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
 * signal an error).
 */

static
int decode(unsigned char const *start, unsigned long length)
{
  struct buffer buffer;
  struct mad_decoder decoder;
  int result;

  /* initialize our private message structure */

  buffer.start  = start;
  buffer.length = length;

  /* configure input, output, and error functions */

  mad_decoder_init(&decoder, &buffer,
		   input, 0 /* header */, 0 /* filter */, output,
		   error, 0 /* message */);

  /* start decoding */

  result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

  //结束fft线程
  decode_finish = 1;

  /* release the decoder */

  mad_decoder_finish(&decoder);

  return result;
}
